15. Subclassing models
You can subclass another model to create a copy of it that behaves slightly differently.
Model source code
from django.core import meta
# From the "Bare-bones model" example
from django.models.basic import Article
# From the "Adding __repr__()" example
from django.models.repr import Article as ArticleWithRepr
# From the "Specifying ordering" example
from django.models.ordering import Article as ArticleWithOrdering
# This uses all fields and metadata from Article and
# adds a "section" field.
class ArticleWithSection(Article):
section = meta.CharField(maxlength=30)
class META:
module_name = 'subarticles1'
# This uses all fields and metadata from Article but
# removes the "pub_date" field.
class ArticleWithoutPubDate(Article):
class META:
module_name = 'subarticles2'
remove_fields = ('pub_date',)
# This uses all fields and metadata from Article but
# overrides the "pub_date" field.
class ArticleWithFieldOverride(Article):
pub_date = meta.DateField() # overrides the old field, a DateTimeField
class META:
module_name = 'subarticles3'
# No need to add remove_fields = ('pub_date',)
# This uses all fields and metadata from ArticleWithRepr and
# makes a few additions/changes.
class ArticleWithManyChanges(ArticleWithRepr):
section = meta.CharField(maxlength=30)
is_popular = meta.BooleanField()
pub_date = meta.DateField() # overrides the old field, a DateTimeField
class META:
module_name = 'subarticles4'
# This uses all fields from ArticleWithOrdering but
# changes the ordering parameter.
class ArticleWithChangedMeta(ArticleWithOrdering):
class META:
module_name = 'subarticles5'
ordering = ('headline', 'pub_date')
# These two models don't define a module_name.
class NoModuleNameFirst(Article):
section = meta.CharField(maxlength=30)
class NoModuleNameSecond(Article):
section = meta.CharField(maxlength=30)
API reference
ArticleWithSection objects have the following methods:
- delete()
- get_next_by_pub_date()
- get_previous_by_pub_date()
- save()
ArticleWithoutPubDate objects have the following methods:
- delete()
- get_next_by_pub_date()
- get_previous_by_pub_date()
- save()
ArticleWithFieldOverride objects have the following methods:
- delete()
- get_next_by_pub_date()
- get_previous_by_pub_date()
- save()
ArticleWithManyChanges objects have the following methods:
- delete()
- get_next_by_pub_date()
- get_previous_by_pub_date()
- save()
ArticleWithChangedMeta objects have the following methods:
- delete()
- get_next_by_pub_date()
- get_previous_by_pub_date()
- save()
NoModuleNameFirst objects have the following methods:
- delete()
- get_next_by_pub_date()
- get_previous_by_pub_date()
- save()
NoModuleNameSecond objects have the following methods:
- delete()
- get_next_by_pub_date()
- get_previous_by_pub_date()
- save()
Sample API usage
This sample code assumes the above models have been saved in a file examplemodel.py.
>>> from django.models.examplemodel import subarticles1, subarticles2, subarticles3, subarticles4, subarticles5, nomodulenamefirsts, nomodulenameseconds # No data is in the system yet. >>> subarticles1.get_list() [] >>> subarticles2.get_list() [] >>> subarticles3.get_list() [] # Create an ArticleWithSection. >>> from datetime import date, datetime >>> a1 = subarticles1.ArticleWithSection(headline='First', pub_date=datetime(2005, 8, 22), section='News') >>> a1.save() >>> a1>>> a1.id 1 >>> a1.headline 'First' >>> a1.pub_date datetime.datetime(2005, 8, 22, 0, 0) # Retrieve it again, to prove the fields have been saved. >>> a1 = subarticles1.get_object(pk=1) >>> a1.headline 'First' >>> a1.pub_date datetime.datetime(2005, 8, 22, 0, 0) >>> a1.section 'News' # Create an ArticleWithoutPubDate. >>> a2 = subarticles2.ArticleWithoutPubDate(headline='Second') >>> a2.save() >>> a2 >>> a2.id 1 >>> a2.pub_date Traceback (most recent call last): ... AttributeError: 'ArticleWithoutPubDate' object has no attribute 'pub_date' # Retrieve it again, to prove the fields have been saved. >>> a2 = subarticles2.get_object(pk=1) >>> a2.headline 'Second' >>> a2.pub_date Traceback (most recent call last): ... AttributeError: 'ArticleWithoutPubDate' object has no attribute 'pub_date' # Create an ArticleWithFieldOverride. >>> a3 = subarticles3.ArticleWithFieldOverride(headline='Third', pub_date=date(2005, 8, 22)) >>> a3.save() >>> a3 >>> a3.id 1 >>> a3.pub_date datetime.date(2005, 8, 22) # Retrieve it again, to prove the fields have been saved. >>> a3 = subarticles3.get_object(pk=1) >>> a3.headline 'Third' >>> a3.pub_date datetime.date(2005, 8, 22) # Create an ArticleWithManyChanges. >>> a4 = subarticles4.ArticleWithManyChanges(headline='Fourth', section='Arts', ... is_popular=True, pub_date=date(2005, 8, 22)) >>> a4.save() # a4 inherits __repr__() from its parent model (ArticleWithRepr). >>> a4 Fourth # Retrieve it again, to prove the fields have been saved. >>> a4 = subarticles4.get_object(pk=1) >>> a4.headline 'Fourth' >>> a4.section 'Arts' >>> a4.is_popular == True True >>> a4.pub_date datetime.date(2005, 8, 22) # Test get_list(). >>> subarticles1.get_list() [ ] >>> subarticles2.get_list() [ ] >>> subarticles3.get_list() [ ] >>> subarticles4.get_list() [Fourth] # Create a couple of ArticleWithChangedMeta objects. >>> a5 = subarticles5.ArticleWithChangedMeta(headline='A', pub_date=datetime(2005, 3, 1)) >>> a5.save() >>> a6 = subarticles5.ArticleWithChangedMeta(headline='B', pub_date=datetime(2005, 4, 1)) >>> a6.save() >>> a7 = subarticles5.ArticleWithChangedMeta(headline='C', pub_date=datetime(2005, 5, 1)) >>> a7.save() # Ordering has been overridden, so objects are ordered # by headline ASC instead of pub_date DESC. >>> subarticles5.get_list() [A, B, C] >>> nomodulenamefirsts.get_list() [] >>> nomodulenameseconds.get_list() []
Comments
Antonio September 10, 2005 at 7:19 a.m.
This is nice but what if you want to be polymorphic about the calls to Article. That is, what if I want to define a model method say Article.get_layout_size() that does different things depending on which subclass is implementing it. But I do not want to have to grovel through and create specific instances of my model subclasses; that is, all I want to do is articles.get_object(pk=12) and get back an appropriate subclass that I can treat as Article without knowing the implementation subtype. Can I do this somehow?
Sokolov Yura September 11, 2005 at 1:10 p.m.
I have a lot of classes share same peaces.
One of this peaces:
....time_from=meta.DateTimeField()
....time_to=meta.DateTimeField(default=datetime(3000,1,1,0,0,0))
Another:
....description=meta.TextField()
....def __repr__(self):
........return self.description
Will following code work?
class TimePeriod:
....time_from=meta.DateTimeField()
....time_to=meta.DateTimeField(default=datetime(3000,1,1,0,0,0))
class Description:
....description=meta.TextField()
....def __repr__(self):
........return self.description
class SomeIdent(meta.Model,TimePeriod,Description)
....value=meta.TextField()
class SomeType(meta.Model,Description):
....value=meta.TextField()
Would it be equally (in Some.... behavior) to:
class SomeIdent(meta.Model)
....time_from=meta.DateTimeField()
....time_to=meta.DateTimeField(default=datetime(3000,1,1,0,0,0))
....value=meta.TextField()
....description=meta.TextField()
....def __repr__(self):
........return self.description
class SomeType(meta.Model,Description):
....value=meta.TextField()
....description=meta.TextField()
....def __repr__(self):
........return self.description
?
Post a comment
Note: Please only use the comments for questions/critcisms/suggestions on the docs; if you experience errors please file a ticket, ask in the IRC channel, or post to the django-users list. Comments will be periodically reviewed, integrated into the documentation proper, and removed.

Rachel Willmer September 1, 2005 at 3:32 a.m.
It might be worth mentioning that if you want the right name to appear in the admin panel, you need to set verbose_name as well as module_name. Otherwise you get the subclass appearing in the admin page, but it uses the superclass name.